package com.pacvue.handler;

import java.util.Collections;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class RedisRateLimiterAcquireTokenHandler extends AbstractRateLimiterAcquireTokenHandler {

    private final RedisTemplate<String, String> rateLimiterRedisTemplate;
    private final DefaultRedisScript<Long> rateLimiterScript;

    public RedisRateLimiterAcquireTokenHandler(RedisTemplate<String, String> rateLimiterRedisTemplate, DefaultRedisScript<Long> rateLimiterScript) {
        this.rateLimiterRedisTemplate = rateLimiterRedisTemplate;
        this.rateLimiterScript = rateLimiterScript;
        // 预热脚本，避免首次执行延迟
        warmupScript();
    }
    
    /**
     * 预热脚本，提高首次执行性能
     */
    private void warmupScript() {
        try {
            log.info("开始预热Redis限流脚本...");
            long startTime = System.currentTimeMillis();
            
            // 执行一次预热调用
            rateLimiterRedisTemplate.execute(
                rateLimiterScript,
                Collections.singletonList("warmup_key"),
                "1",
                "1"
            );
            
            long warmupTime = System.currentTimeMillis() - startTime;
            log.info("Redis限流脚本预热完成，耗时: {}ms", warmupTime);
            
        } catch (Exception e) {
            log.warn("Redis限流脚本预热失败: {}", e.getMessage());
        }
    }

    /**
     * Redis令牌桶算法
     * @param key
     * @param capacity
     * @param rate
     * @return
     */
    @Override
    public boolean tryAcquire(String key, int capacity, double rate) {
        try {
            Long result = rateLimiterRedisTemplate.execute(
                rateLimiterScript,
                Collections.singletonList(key),
                String.valueOf(capacity),
                String.valueOf(rate)
            );
            
            boolean allowed = result != null && result == 1L;
            if (log.isDebugEnabled()) {
                log.debug("Redis限流检查 - key: {}, capacity: {}, rate: {}, result: {}", key, capacity, rate, allowed);
            }
            return allowed;
            
        } catch (RedisConnectionFailureException e) {
            log.error("Redis连接失败，限流检查失败 - key: {}, error: {}", key, e.getMessage());
            // Redis连接失败时，为了系统可用性，允许请求通过
            return true;
        } catch (DataAccessException e) {
            log.error("Redis数据访问异常，限流检查失败 - key: {}, error: {}", key, e.getMessage());
            // Redis数据访问异常时，为了系统可用性，允许请求通过
            return true;
        } catch (Exception e) {
            log.error("Redis限流检查发生未知异常 - key: {}, error: {}", key, e.getMessage(), e);
            // 未知异常时，为了系统可用性，允许请求通过
            return true;
        }
    }
}
